#region File Description
//-----------------------------------------------------------------------------
// MenuEntry.cs
//
// XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements

using System;
using Epitech.Krisk.Xna.ScreenManagerLib.ScreenManager;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

#endregion

namespace Epitech.Krisk.Xna.ScreenManagerLib.Widget
{
    /// <summary>
    /// Helper class represents a single entry in a MenuScreen. By default this
    /// just draws the entry text string, but it can be customized to display menu
    /// entries in different ways. This also provides an event that will be raised
    /// when the menu entry is selected.
    /// </summary>
    public class MenuEntry
    {
        #region Fields

        /// <summary>
        /// The text rendered for this entry.
        /// </summary>
        protected string text;
        readonly bool _fromAsset;
        private Texture2D _asset;
        ContentManager _content;
        public LayoutEntry ParentLayout { get; set; }

        /// <summary>
        /// Tracks a fading selection effect on the entry.
        /// </summary>
        /// <remarks>
        /// The entries transition out of the selection effect when they are deselected.
        /// </remarks>
        float _selectionFade;

        #endregion

        #region Properties


        /// <summary>
        /// Gets or sets the text of this menu entry.
        /// </summary>
        public string Text
        {
            get { return text; }
            set { text = value; }
        }

        public LayoutEntry Parent { get; set; }

        /// <summary>
        /// Gets or sets the position at which to draw this menu entry.
        /// </summary>
        public Vector2 Position { get; set; }

        #endregion

        #region Events


        /// <summary>
        /// Event raised when the menu entry is selected.
        /// </summary>
        public event EventHandler<PlayerIndexEventArgs> Selected;


        /// <summary>
        /// Method for raising the Selected event.
        /// </summary>
        protected internal virtual void OnSelectEntry(PlayerIndex playerIndex)
        {
            if (Selected != null)
                Selected(this, new PlayerIndexEventArgs(playerIndex));
        }


        #endregion

        #region Initialization

        public Rectangle AreaRectangle { get; set; }

        /// <summary>
        /// Constructs a new menu entry with the specified text.
        /// </summary>
        public MenuEntry(string text)
        {
            this.text = text;
            DefaultColor = Color.White;
            SelectedColor = Color.Yellow;
            IsPulse = true;
            FontSize = 1;
        }

        public MenuEntry(string asset, string overtext)
        {
            this._fromAsset = true;
            this.text = asset;
            Textover = overtext;
            DefaultColor = Color.White;
            SelectedColor = Color.Yellow;
            IsPulse = true;
            FontSize = 1;
        }

        public MenuEntry(string asset, bool fromAsset)
        {
            if (fromAsset)
                this._fromAsset = true;
            this.text = asset;
            DefaultColor = Color.White;
            SelectedColor = Color.Yellow;
            IsPulse = true;
            FontSize = 1;
        }

        public virtual void LoadContent(GameScreen currentScreen)
        {
            if (_fromAsset)
            {
                if (_content == null)
                    _content = new ContentManager(currentScreen.ScreenManager.Game.Services, "Content");
                Asset = _content.Load<Texture2D>(text);
                AreaRectangle = new Rectangle((int)Position.X, (int)Position.Y, Asset.Width, Asset.Height);
            }
            else
                AreaRectangle = new Rectangle((int)Position.X, (int)Position.Y - (int)currentScreen.ScreenManager.Font.MeasureString(text).Y / 2, (int)currentScreen.ScreenManager.Font.MeasureString(text).X, (int)currentScreen.ScreenManager.Font.MeasureString(text).Y);
        }

        public virtual void UnloadContent()
        {
            if (_fromAsset)
                _content.Unload();
        }

        protected bool isSelect = false;
        private string _textover = String.Empty;
        private Vector2 _lastPos = Vector2.Zero;

        #endregion

        #region Update and Draw

        public Color SelectedColor { get; set; }
        public Color DefaultColor { get; set; }
        public bool IsPulse { get; set; }
        public float FontSize { get; set; }

        public string Textover
        {
            get { return _textover; }
            set { _textover = value; }
        }

        public Texture2D Asset
        {
            get { return _asset; }
            set { _asset = value; }
        }

        /// <summary>
        /// Updates the menu entry.
        /// </summary>
        public virtual void Update(GameScreen screen, bool isSelected, GameTime gameTime)
        {
            // there is no such thing as a selected item on Windows Phone, so we always
            // force isSelected to be false
            isSelect = isSelected;
#if WINDOWS_PHONE
            isSelected = false;
#endif

            if (_lastPos != Position)
            {
                //if (_fromAsset && String.IsNullOrEmpty(Textover))
                    AreaRectangle = new Rectangle((int)Position.X, (int)Position.Y, AreaRectangle.Width, AreaRectangle.Height);                
                //else
                //    AreaRectangle = new Rectangle((int)Position.X, (int)Position.Y - AreaRectangle.Height / 2, AreaRectangle.Width, AreaRectangle.Height);                
            }


            // When the menu selection changes, entries gradually fade between
            // their selected and deselected appearance, rather than instantly
            // popping to the new state.
            float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;

            _selectionFade = isSelect ? Math.Min(_selectionFade + fadeSpeed, 1) : Math.Max(_selectionFade - fadeSpeed, 0);
            _lastPos = Position;
        }


        /// <summary>
        /// Draws the menu entry. This can be overridden to customize the appearance.
        /// </summary>
        public virtual void Draw(GameScreen screen, bool isSelected, GameTime gameTime)
        {
            // there is no such thing as a selected item on Windows Phone, so we always
            // force isSelected to be false
#if WINDOWS_PHONE
            isSelected = false;
#endif

            // Draw the selected entry in yellow, otherwise white.
            Color color = isSelected ? SelectedColor : DefaultColor;

            // Pulsate the size of the selected menu entry.
            double time = gameTime.TotalGameTime.TotalSeconds;

            float scale = FontSize;
            if (IsPulse)
            {
                float pulsate = (float)Math.Sin(time * 6) + 1;

                scale = FontSize + pulsate * 0.05f * _selectionFade;
            }

            // Modify the alpha to fade text out during transitions.
            color *= screen.TransitionAlpha;


            // Draw text, centered on the middle of each line.
            ScreenManager.ScreenManager screenManager = screen.ScreenManager;
            SpriteBatch spriteBatch = screenManager.SpriteBatch;
            SpriteFont font = screenManager.Font;

            Vector2 origin = new Vector2(0, font.LineSpacing * FontSize / 2);
            if (_fromAsset && String.IsNullOrEmpty(Textover))
            {
                spriteBatch.Draw(Asset, Position, Asset.Bounds, color, 0,
                                Vector2.Zero, scale, SpriteEffects.None, 0);
            }
            else if (!String.IsNullOrEmpty(Textover) && _fromAsset)
            {
                spriteBatch.Draw(Asset, Position, null, Color.White, 0,
                                Vector2.Zero, scale, SpriteEffects.None, 0);

                Vector2 textpos = Position;

                if (Asset != null) textpos.X += Asset.Width/2 - font.MeasureString(Textover).X/2;

                spriteBatch.DrawString(font, Textover, textpos, color, 0,
                   Vector2.Zero, scale, SpriteEffects.None, 0);
            }
            else
                spriteBatch.DrawString(font, text, Position, color, 0,
                                   Vector2.Zero, scale, SpriteEffects.None, 0);
        }

        /// <summary>
        /// Queries how much space this menu entry requires.
        /// </summary>
        public virtual int GetHeight(GameScreen screen)
        {
            if (_fromAsset)
                return this.Asset.Bounds.Height;
            else
                return (int)((float)screen.ScreenManager.Font.LineSpacing * FontSize);
        }

        public virtual void HandleInput(GameScreen currentScreen, InputState input)
        {
            isSelect = AreaRectangle.Contains((int) input.MousePosition().X, (int) input.MousePosition().Y);
            if (isSelect && ParentLayout != null)
                ParentLayout.SelectedIndex = ParentLayout.MenuEntries.IndexOf(this);
            else if (isSelect && ParentLayout == null)
            {
                PlayerIndex tmp;

                if (input.IsNewMouseButtonDown(MouseButton.Left)
                    || input.IsNewButtonPress(Buttons.A, null, out tmp))
                    OnSelectEntry(PlayerIndex.One);
            }
        }

        /// <summary>
        /// Queries how wide the entry is, used for centering on the screen.
        /// </summary>
        public virtual int GetWidth(GameScreen screen)
        {
            if (_fromAsset)
                return this.Asset.Bounds.Width;
            return (int)((float)screen.ScreenManager.Font.MeasureString(Text).X * FontSize);
        }


        #endregion
    }
}
